home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 1 / Amiga Tools.iso / disk-tools / cd-tools / amicdrom / main.c < prev    next >
C/C++ Source or Header  |  1994-06-06  |  30KB  |  1,023 lines

  1. /* main.c:
  2.  *
  3.  * Interactive test program for the ISO- and Rock-Ridge-support
  4.  * routines.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  * 
  14.  * 17-Feb-94   fmu   Fixed typo.
  15.  * 28-Nov-93   fmu   Improved "cdrom d" command.
  16.  * 12-Oct-93   fmu   "Show path table" function removed.
  17.  * 09-Oct-93   fmu   Open utility.library.
  18.  */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23.  
  24. #include <dos/var.h>
  25. #include <clib/dos_protos.h>
  26. #include <clib/exec_protos.h>
  27.  
  28. #include "cdrom.h"
  29. #include "iso9660.h"
  30. #include "rock.h"
  31. #include "hfs.h"
  32.  
  33. #ifdef AZTEC_C
  34. #include <pragmas/dos_lib.h>
  35. #include <pragmas/exec_lib.h>
  36. #endif
  37.  
  38. #ifdef LATTICE
  39. #include <pragmas/dos_pragmas.h>
  40. #include <pragmas/exec_pragmas.h>
  41. extern struct Library *SysBase, *DOSBase;
  42. #endif
  43.  
  44. #if defined(_DCC) && defined(REGISTERED)
  45. #include <pragmas/dos_pragmas.h>
  46. #include <pragmas/exec_pragmas.h>
  47. extern struct Library *SysBase, *DOSBase;
  48. #endif
  49.  
  50. #define STD_BUFFERS 10
  51. #define FILE_BUFFERS 5
  52.  
  53. #ifdef DEBUG_SECTORS
  54. void dbprintf (char *p_dummy, ...)
  55. {
  56. }
  57. #endif
  58.  
  59. CDROM *cd = NULL;
  60. char g_the_device[80];
  61. int g_the_unit;
  62. int g_trackdisk = 0;
  63. t_ulong g_memory_type = MEMF_CHIP;
  64.  
  65. struct Library *UtilityBase;
  66.  
  67. void Cleanup (void)
  68. {
  69.   if (cd)
  70.     Cleanup_CDROM (cd);
  71.  
  72.   if (UtilityBase)
  73.     CloseLibrary (UtilityBase);
  74. }
  75.  
  76. void Usage (void)
  77. {
  78.   fprintf (stderr,
  79.     "Usage: cdrom command [parameters]\n"
  80.     "Commands:\n"
  81.     "  a                Show information on CDROM drive\n"
  82.     "  b                Read table of contents\n"
  83.     "  c name           Show contents of file 'name'\n"
  84.     "  d[rl] dir        Show contents of directory 'dir' (use ISO names)\n"
  85.     "                   r=also show subdirectories, l=show additional information\n"
  86.     "  e[r[l|L]] dir    Show contents of directory 'dir' (use Rock Ridge names)\n"
  87.     "                   r=also show subdirectories, l=show system use field names\n"
  88.     "                   L=show names and contents of system use fields\n"
  89.     "  f dir name       Change to directory 'dir' and try to find object 'name'\n"
  90.     "  i                Check which protocol is used\n"
  91.     "  j [01]           0=start audio, 1=stop motor\n"
  92.     "  m num            Read catalog node 'num' (MacHFS only)\n"
  93.     "  o name           Try to open object 'name'\n"
  94.     "  r                Read contents of root directory\n"
  95.     "  s num [cnt]      Read 'cnt' sectors, starting at sector 'num'\n"
  96.     "  t name           Try to open parent of object 'name'\n"
  97.     "  v                Read primary volume descriptor\n"
  98.     "  x dens [length]  Select mode: dens=density code,\n"
  99.     "                   length=block length (default: 2048)\n"
  100.     "  z                Send test unit ready command\n"
  101.     "Use \":\" as the name of the root directory\n"
  102.     );
  103.   exit (1);
  104. }
  105.  
  106. char *MKSTR (char *p_in, int p_length, char *p_out)
  107. {
  108.   char *res = p_out;
  109.   int len = p_length;
  110.   int i;
  111.   
  112.   while (len && p_in[len-1] == ' ')
  113.     len--;
  114.  
  115.   for (i=0; i<len; i++)
  116.     *p_out++ = *p_in++;
  117.     
  118.   *p_out = 0;
  119.   
  120.   return res;
  121. }
  122.  
  123. void Show_Flags (unsigned char p_flags)
  124. {
  125.   if (p_flags & 1)
  126.     printf ("existence ");
  127.   if (p_flags & 2)
  128.     printf ("directory ");
  129.   if (p_flags & 4)
  130.     printf ("associated ");
  131.   if (p_flags & 8)
  132.     printf ("record ");
  133.   if (p_flags & 16)
  134.     printf ("protection ");
  135.   if (p_flags & 128)
  136.     printf ("multi-extent ");
  137. }
  138.  
  139. void Show_Directory_Record (directory_record *p_dir)
  140. {
  141.   char buf[256];
  142.  
  143.   printf ("Extended Attr Record Length: %d\n", (int) p_dir->ext_attr_length);
  144.   printf ("Location of Extent:          %lu\n", p_dir->extent_loc_m);
  145.   printf ("Data Length:                 %lu\n", p_dir->data_length_m);
  146.   printf ("Recording Date and Time:     %02d.%02d.19%02d %02d:%02d:%02d %+d\n",
  147.         (int) p_dir->day, (int) p_dir->month, (int) p_dir->year,
  148.       (int) p_dir->hour, (int) p_dir->minute, (int) p_dir->second,
  149.       (int) p_dir->tz);
  150.   printf ("Flags:                       %d (", (int) p_dir->flags);
  151.   Show_Flags (p_dir->flags);
  152.   printf (")\n");
  153.   printf ("File Unit Size:              %d\n", (int) p_dir->file_unit_size);
  154.   printf ("Gap Size:                    %d\n", (int) p_dir->gap_size);
  155.   printf ("Volume Sequence Number:      %hu\n", p_dir->sequence_m);
  156.   printf ("File Identifier:             ");
  157.   if (p_dir->file_id[0] == 0)
  158.     printf ("(00)\n");
  159.   else if (p_dir->file_id[0] == 1)
  160.     printf ("(01)\n");
  161.   else
  162.     printf ("%s\n", MKSTR (p_dir->file_id, p_dir->file_id_length, buf));
  163. }
  164.  
  165. void Find_Block_Starting_With (CDROM *p_cd, int p_val)
  166. {
  167.   unsigned long sec = 0;
  168.   int cmp;
  169.   int i;
  170.   
  171.   for (;;) {
  172.     if (!Read_Sector (p_cd, sec)) {
  173.       fprintf (stderr, "cannot read sector 16\n");
  174.       exit (1);
  175.     }
  176.     for (i=0; i<4; i++) {
  177.       cmp = p_cd->buffer[i<<9] * 256 + p_cd->buffer[(i<<9)+1];
  178.       if (cmp == p_val)
  179.         printf ("sector %lu, block %d\n", sec, i);
  180.     }
  181.     sec++;
  182.   }
  183. }
  184.  
  185. void Show_Primary_Volume_Descriptor (CDROM *p_cd)
  186. {
  187.   prim_vol_desc *pvd;
  188.   char buf[129];
  189.   int blk;
  190.   t_mdb mdb;
  191.   t_hdr_node hdr;
  192.   int skip;
  193.   t_ulong offset;
  194.   int protocol;
  195.   t_bool hfs;
  196.   
  197.   hfs = Uses_HFS_Protocol (p_cd, &skip);
  198.   protocol = Which_Protocol (p_cd, TRUE, &skip, &offset);
  199.   
  200.   if (protocol == PRO_UNKNOWN) {
  201.     printf ("Unknown protocol\n");
  202.     return;
  203.   }
  204.   
  205.   if (protocol == PRO_HIGH_SIERRA) {
  206.     printf ("High sierra protocol (not supported)\n");
  207.   }
  208.   
  209.   if ((protocol == PRO_ROCK || protocol == PRO_ISO) && hfs)
  210.     printf ("Multi-platform disk: HFS & ISO\n");
  211.  
  212.   if (protocol == PRO_ROCK)
  213.     printf ("Rock Ridge extensions available, skip size = %d\n", skip);
  214.   
  215.   if (protocol == PRO_ISO)
  216.     printf ("Data track offset = %lu\n", offset);
  217.  
  218.   if (protocol == PRO_ISO || protocol == PRO_ROCK) {
  219.  
  220.     if (!Read_Sector (p_cd, 16 + offset)) {
  221.       fprintf (stderr, "cannot read sector %lu\n", 16 + offset);
  222.       exit (1);
  223.     }
  224.  
  225.     pvd = (prim_vol_desc *) p_cd->buffer;
  226.     printf ("--- ISO-9660: ---\n");
  227.     printf ("Volume Descriptor Type:          %d\n", (int) pvd->type);
  228.     printf ("Standard Identifier:             %s\n", MKSTR (pvd->id,5,buf));
  229.     printf ("Volume Descriptor Version:       %d\n", (int) pvd->version);
  230.     printf ("System Identifier:               %s\n", MKSTR (pvd->system_id,32,buf));
  231.     printf ("Volume Identifier:               %s\n", MKSTR (pvd->volume_id,32,buf));
  232.     printf ("Volume Space Size:               %lu\n", pvd->space_size_m);
  233.     printf ("Volume Set Size:                 %hu\n", pvd->set_size_m);
  234.     printf ("Volume Sequence Number:          %hu\n", pvd->sequence_m);
  235.     printf ("Logical Block Size:              %hu\n", pvd->block_size_m);
  236.     printf ("Path Table Size:                 %lu\n", pvd->path_size_m);
  237.     printf ("Location of Occ of M Path Table: %lu\n", pvd->m_table); 
  238.     printf ("Location of Occ of Opt M Path T: %lu\n", pvd->opt_m_table);
  239.     printf ("Volume Set Identifier:           %s\n",
  240.                       MKSTR (pvd->volume_set_id,128,buf));  
  241.     printf ("Publisher Identifier:            %s\n",
  242.                       MKSTR (pvd->publisher_id,128,buf)); 
  243.     printf ("Data Preparer Identifier:        %s\n",
  244.                       MKSTR (pvd->data_preparer,128,buf));
  245.     printf ("Application Identifier:          %s\n",
  246.                       MKSTR (pvd->application_id,128,buf));
  247.     printf ("Copyright File Identifier:       %s\n",
  248.                       MKSTR (pvd->copyright,37,buf));
  249.     printf ("Abstract File Identifier:        %s\n",
  250.                       MKSTR (pvd->abstract_file_id,37,buf));
  251.     printf ("Bibliographic File Identifier:   %s\n",
  252.                       MKSTR (pvd->bibliographic_id,37,buf));
  253.     printf ("File Structure Version:          %d\n",
  254.                       (int) pvd->file_structure_version);
  255.     printf ("ROOT DIRECTORY RECORD:\n");
  256.     Show_Directory_Record (&pvd->root);
  257.   }
  258.   
  259.   if (hfs) {
  260.     if ((blk = HFS_Find_Master_Directory_Block (p_cd, &mdb)) < 0) {
  261.       printf ("No master directory block found\n");
  262.       exit (1);
  263.     }
  264.     printf ("--- MacHFS: ---\n");
  265.     printf ("Master directory block located at block %d\n", blk);
  266.     printf ("Volume signature:               0x%hx\n", mdb.SigWord);
  267.     printf ("Date/Time of creation:          %lu\n", mdb.CrDate);
  268.     printf ("Date/Time of last modification: %lu\n", mdb.LsMod);
  269.     printf ("Volume attributes:              0x%hx\n", mdb.Atrb);
  270.     printf ("Number of files in root dir:    %u\n", mdb.NmFls);
  271.     printf ("Allocation block size:          %lu bytes\n", mdb.AlBlkSiz);
  272.     printf ("Loc of first allocation block:  %u\n", mdb.AlBlSt);
  273.     printf ("Volume name:                    %s\n",
  274.                     MKSTR ((char *) mdb.VolName, mdb.VolNameLen,buf));
  275.     printf ("Number of files in volume:      %lu\n", mdb.FilCnt);
  276.     printf ("Number of dirs in volume:       %lu\n", mdb.DirCnt);
  277.     printf ("Size of catalog file:           %lu allocation blocks\n",
  278.                             mdb.CTFlSize);
  279.     printf ("Extent record for catalog file:\n");
  280.     printf ("  1. allocation block: %10lu   length: %10lu\n",
  281.                     mdb.CTExtRec[0].StABN, mdb.CTExtRec[0].NumABlks);
  282.     printf ("  2. allocation block: %10lu   length: %10lu\n",
  283.                     mdb.CTExtRec[1].StABN, mdb.CTExtRec[1].NumABlks);
  284.     printf ("  3. allocation block: %10lu   length: %10lu\n",
  285.                     mdb.CTExtRec[2].StABN, mdb.CTExtRec[2].NumABlks);
  286.     if (!HFS_Get_Header_Node (p_cd, blk, &mdb, &hdr))
  287.       printf ("*** Cannot read header node!!!\n");
  288.     printf ("Header node:\n");
  289.     printf ("Depth of tree:                  %u\n", hdr.Depth);
  290.     printf ("Number of root node:            %lu\n", hdr.Root);
  291.     printf ("Number of leaf records in tree: %lu\n", hdr.NRecs);
  292.     printf ("Number of first leaf node:      %lu\n", hdr.FNode);
  293.     printf ("Number of last leaf node:       %lu\n", hdr.LNode);
  294.   }
  295. }
  296.  
  297. void Show_Directory (CDROM *p_cd, unsigned long p_location, unsigned long p_length)
  298. {
  299.   int cnt = 0;
  300.   int pos = 0;
  301.   
  302.   if (!Read_Sector (p_cd, p_location)) {
  303.     fprintf (stderr, "cannot read sector %lu\n", p_location);
  304.     exit (1);
  305.   }
  306.  
  307.   while (cnt < p_length) {
  308.     directory_record *dir = (directory_record *) (p_cd->buffer + pos);
  309.     
  310.     if (dir->length == 0)
  311.       break;
  312.     Show_Directory_Record (dir);
  313.     cnt += dir->length;
  314.     pos += dir->length;
  315.     if (cnt < p_length) {
  316.       printf ("------------------------------------------------------------\n");
  317.       if (pos >= 2048) {
  318.         if (!Read_Sector (p_cd, ++p_location)) {
  319.           fprintf (stderr, "cannot read sector %lu\n", p_location);
  320.           exit (1);
  321.         }
  322.         pos = 0;
  323.       }
  324.     }
  325.   }
  326. }
  327.  
  328. void Show_Root_Directory (CDROM *p_cd)
  329. {
  330.   prim_vol_desc *pvd;
  331.   
  332.   if (!Read_Sector (p_cd, 16)) {
  333.     fprintf (stderr, "cannot read sector 16\n");
  334.     exit (1);
  335.   }
  336.  
  337.   pvd = (prim_vol_desc *) p_cd->buffer;
  338.  
  339.   Show_Directory (p_cd, pvd->root.extent_loc_m, pvd->root.data_length_m);
  340. }
  341.  
  342. void Check_Protocol (CDROM *p_cd)
  343. {
  344.   int skip;
  345.   t_ulong offset;
  346.  
  347.   switch (Which_Protocol (p_cd, TRUE, &skip, &offset)) {
  348.   case PRO_ROCK:
  349.     printf ("Rock Ridge protocol, skip length = %d\n", skip);
  350.     break;
  351.   case PRO_ISO:
  352.     printf ("ISO-9660 protocol, offset = %lu\n", offset);
  353.     break;
  354.   case PRO_HFS:
  355.     printf ("Macintosh HFS protocol\n");
  356.     break;
  357.   case PRO_HIGH_SIERRA:
  358.     printf ("High Sierra protocol\n");
  359.     break;
  360.   default:
  361.     printf ("Unknown protocol, iso_errno = %d\n", iso_errno);
  362.     break;
  363.   }
  364. }
  365.  
  366. void Try_To_Open (CDROM *p_cd, char *p_directory, char *p_name)
  367. {
  368.   VOLUME *vol;
  369.   CDROM_OBJ *top = NULL;
  370.   CDROM_OBJ *home;
  371.   CDROM_OBJ *obj;
  372.   CDROM_OBJ *parent;
  373.   char pathname[256];
  374.  
  375.   if (!(vol = Open_Volume (p_cd, 1))) {
  376.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  377.     exit (1);
  378.   }
  379.  
  380.   if (p_directory && p_directory != (char *) -1) {
  381.     if (!(top = Open_Top_Level_Directory (vol))) {
  382.       fprintf (stderr, "cannot open top level directory\n");
  383.       Close_Volume (vol);
  384.       exit (1);
  385.     }
  386.     
  387.     if (!(home = Open_Object (top, p_directory))) {
  388.       fprintf (stderr, "cannot open top level directory\n");
  389.       Close_Object (top);
  390.       Close_Volume (vol);
  391.       exit (1);
  392.     }
  393.   } else {
  394.     if (!(home = Open_Top_Level_Directory (vol))) {
  395.       fprintf (stderr, "cannot open home directory;"
  396.                        " iso_errno = %d\n", iso_errno);
  397.       Close_Volume (vol);
  398.       exit (1);
  399.     }
  400.   }
  401.  
  402.   if (obj = Open_Object (home, p_name)) {
  403.     CDROM_INFO info;
  404.     printf ("%s '%s' found, location = %lu\n",
  405.             obj->symlink_f ? "Symbolic link" :
  406.             obj->directory_f ? "Directory" : "File",
  407.             p_name, Location (obj));
  408.     if (obj->symlink_f) {
  409.       char linkname[256];
  410.       printf ("Link to ");
  411.       if (Get_Link_Name (obj, linkname, sizeof (linkname)))
  412.         printf ("'%s'\n", linkname);
  413.       else
  414.         printf ("unknown file or directory\n");
  415.     }
  416.     if (Full_Path_Name (obj, pathname, sizeof (pathname)))
  417.       printf ("Full path name: %s\n", pathname);
  418.     else
  419.       printf ("Full path name unknown\n");
  420.     if (CDROM_Info (obj, &info)) {
  421.       printf ("INFO Name = ");
  422.       fwrite (info.name, info.name_length, 1, stdout);
  423.       printf ("\n");
  424.     } else
  425.       printf ("CANNOT FIND INFO FOR OBJECT!\n");
  426.     if (p_directory == (char *) -1) {
  427.       parent = Find_Parent (obj);
  428.       if (parent) {
  429.         printf ("parent found, location = %lu\n",
  430.             Location (parent));
  431.         Close_Object (parent);
  432.       } else
  433.         printf ("parent not found, iso_errno = %d\n", iso_errno);
  434.     }
  435.     Close_Object (obj);
  436.   } else {
  437.     if (iso_errno == ISOERR_NOT_FOUND)
  438.       printf ("Object '%s' not found\n", p_name);
  439.     else
  440.       printf ("Object '%s': iso_errno = %d\n", p_name, iso_errno);
  441.   }
  442.  
  443.   if (top)
  444.     Close_Object (top);
  445.   Close_Object (home);
  446.   Close_Volume (vol);
  447. }
  448.  
  449. void Show_File_Contents (CDROM *p_cd, char *p_name)
  450. {
  451.   VOLUME *vol;
  452.   CDROM_OBJ *home;
  453.   CDROM_OBJ *obj;
  454. #define THEBUFSIZE 99
  455.   char buffer[THEBUFSIZE];
  456.   int cnt;
  457.  
  458.   if (!(vol = Open_Volume (p_cd, 1))) {
  459.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  460.     exit (1);
  461.   }
  462.  
  463.   if (!(home = Open_Top_Level_Directory (vol))) {
  464.     fprintf (stderr, "cannot open top level directory;"
  465.                      " iso_errno = %d\n", iso_errno);
  466.     Close_Volume (vol);
  467.     exit (1);
  468.   }
  469.  
  470.   if (obj = Open_Object (home, p_name)) {
  471.     for (;;) {
  472.       cnt = Read_From_File (obj, buffer, THEBUFSIZE);
  473.       if (cnt == -1) {
  474.         fprintf (stderr, "cannot read from file!\n");
  475.     break;
  476.       }
  477.       if (cnt == 0)
  478.         break;
  479.       fwrite (buffer, cnt, 1, stdout);
  480.     }
  481.  
  482.     Close_Object (obj);
  483.   } else {
  484.     fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  485.   }
  486.  
  487.   Close_Object (home);
  488.   Close_Volume (vol);
  489.   
  490. }
  491.  
  492. void Print_System_Use_Fields (CDROM *p_cd, directory_record *p_dir,
  493.                   int p_skip_size, int p_long)
  494. {
  495.   int system_use_pos;
  496.   int slen;
  497.   unsigned long length = p_dir->length;
  498.   unsigned char *buf = (unsigned char *) p_dir;
  499.  
  500.   printf ("   system use fields: ");
  501.   if (p_long)
  502.     putchar ('\n');
  503.  
  504.   system_use_pos = 33 + p_dir->file_id_length;
  505.   if (system_use_pos & 1)
  506.     system_use_pos++;
  507.   system_use_pos += p_skip_size;
  508.  
  509.   /* the system use field must be at least 4 bytes long */
  510.   while (system_use_pos + 3 < length) {
  511.     slen = buf[system_use_pos+2];
  512.     /* look for continuation area: */
  513.     if (buf[system_use_pos] == 'C' &&
  514.         buf[system_use_pos+1] == 'E') {
  515.       unsigned long newloc, offset;
  516.       printf ("/ ");
  517.       memcpy (&newloc, buf + system_use_pos + 8, 4);
  518.       memcpy (&offset, buf + system_use_pos + 16, 4);
  519.       memcpy (&length, buf + system_use_pos + 24, 4);
  520.       if (!Read_Sector (p_cd, newloc))
  521.         return;
  522.       buf = p_cd->buffer;
  523.       system_use_pos = offset;
  524.       continue;
  525.     /* look for system use field terminator: */
  526.     } else if (buf[system_use_pos] == 'S' &&
  527.         buf[system_use_pos+1] == 'T') {
  528.       printf ("ST");
  529.       break;
  530.     } else if  (buf[system_use_pos] == 'S' &&
  531.       /* special handling for SL field: */
  532.       buf[system_use_pos+1] == 'L') {
  533.       printf ("SL(%s%d,", (buf[system_use_pos+4] & 1)? "cont " : "",
  534.                     (int) buf[system_use_pos+5]);
  535.       fwrite (buf + system_use_pos + 7, buf[system_use_pos+6], 1, stdout);
  536.       printf (") ");
  537.     } else {
  538.       if (p_long)
  539.         printf ("   ");
  540.       putchar (buf[system_use_pos]);
  541.       putchar (buf[system_use_pos+1]);
  542.       putchar (' ');
  543.       if (p_long) {
  544.         int i;
  545.     for (i=0; i < slen-2; i++) {
  546.       if (i && (i & 15) == 0)
  547.         printf ("\n      ");
  548.       printf ("%2.2x ", (int) buf[system_use_pos+i+2]);
  549.     }
  550.       }
  551.     }
  552.  
  553.     if (p_long)
  554.       putchar ('\n');
  555.  
  556.     system_use_pos += slen;
  557.   }
  558.   
  559.   putchar ('\n');
  560. }
  561.  
  562. void Show_Subdirectory (CDROM_OBJ *p_home, char *p_name, int p_long_info,
  563.             int p_recursive)
  564. {
  565.   CDROM_OBJ *obj;
  566.   CDROM_INFO info;
  567.   VOLUME *vol = p_home->volume;
  568.  
  569.   if (obj = Open_Object (p_home, p_name)) {
  570.     unsigned long offset = 0;
  571.     
  572.     while (Examine_Next (obj, &info, &offset)) {
  573.       directory_record *dir = info.suppl_info;
  574.       fwrite (info.name, info.name_length, 1, stdout);
  575.       if (info.symlink_f)
  576.         printf (" (symbolic link)");
  577.       else if (info.directory_f)
  578.         printf (" (dir)");
  579.       printf ("\n");
  580.       if (p_long_info && dir) {
  581.         printf ("   %02d.%02d.%02d %02d:%02d:%02d  ",
  582.         (int) dir->day,
  583.         (int) dir->month,
  584.         (int) dir->year,
  585.         (int) dir->hour,
  586.         (int) dir->minute,
  587.         (int) dir->second);
  588.     printf ("%lu  ", dir->data_length_m);
  589.     printf ("loc=%lu  ", dir->extent_loc_m);
  590.     Show_Flags (dir->flags);
  591.     putchar ('\n');
  592.         if (dir->ext_attr_length)
  593.       printf ("   contains extended attribute record\n");
  594.     if (dir->gap_size)
  595.       printf ("   is recorded in interleaved mode\n");
  596.     if (vol->protocol == PRO_ROCK)
  597.           Print_System_Use_Fields (vol->cd, dir,
  598.                      ((t_iso_vol_info *) vol->vol_info)->skip,
  599.                    p_long_info == 2);
  600.       }
  601.     }
  602.  
  603.     Close_Object (obj);
  604.   } else {
  605.     fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  606.     return;
  607.   }
  608.  
  609.   if (p_recursive) {
  610.     if (obj = Open_Object (p_home, p_name)) {
  611.       unsigned long offset = 0;
  612.     
  613.       while (Examine_Next (obj, &info, &offset)) {
  614.         if (info.directory_f) {
  615.       char *name = malloc (strlen (p_name) + info.name_length + 2);
  616.       int len;
  617.       if (!name) {
  618.         fprintf (stderr, "out of memory\n");
  619.         exit (1);
  620.       }
  621.       if (Is_Top_Level_Object (obj))
  622.         name[0] = 0;
  623.       else
  624.         sprintf (name, "%s/", p_name);
  625.       len = strlen (name) + info.name_length;
  626.       memcpy (name + strlen (name), info.name, info.name_length);
  627.       name[len] = 0;
  628.       printf ("\n%s:\n", name);
  629.       Show_Subdirectory (p_home, name, p_long_info, TRUE);
  630.       free (name);
  631.         }
  632.       }
  633.       Close_Object (obj);
  634.     } else {
  635.       fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  636.     }
  637.   }
  638.  
  639. }
  640.  
  641. void Show_Dir_Contents (CDROM *p_cd, char *p_name, int p_rock_ridge,
  642.             char *p_options)
  643. {
  644.   VOLUME *vol;
  645.   CDROM_OBJ *home;
  646.   int long_info = strchr (p_options, 'l') ? 1 :
  647.             strchr (p_options, 'L') ? 2 : 0;
  648.   t_bool recursive = (strchr (p_options, 'r') != NULL);
  649.  
  650.   if (!(vol = Open_Volume (p_cd, p_rock_ridge))) {
  651.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  652.     exit (1);
  653.   }
  654.  
  655.   if (!(home = Open_Top_Level_Directory (vol))) {
  656.     fprintf (stderr, "cannot open top level directory;"
  657.                      " iso_errno = %d\n", iso_errno);
  658.     Close_Volume (vol);
  659.     exit (1);
  660.   }
  661.  
  662.   Show_Subdirectory (home, p_name, long_info, recursive);
  663.  
  664.   Close_Object (home);
  665.   Close_Volume (vol);
  666. }
  667.  
  668. void Send_Test_Unit_Ready (CDROM *p_cd)
  669. {
  670.   printf ("result = %d\n", Test_Unit_Ready (p_cd));
  671. }
  672.  
  673. void Show_Sectors (CDROM *p_cd, int p_sector, int p_cnt)
  674. {
  675.   int i, j, s;
  676.   int off;
  677.   
  678.   if (p_sector < 0)
  679.     return;
  680.   
  681.   for (s=0; s<p_cnt; s++) {
  682.     if (!Read_Sector (p_cd, p_sector + s)) {
  683.       fprintf (stderr, "cannot read sector %d\n", p_sector + s);
  684.       exit (1);
  685.     }
  686.     for (off=0, i=0; i<128; i++) {
  687.       printf ("%02x:%03x0: ", s, i);
  688.       for (j=0; j<16; j++)
  689.         printf ("%02x ", (int) p_cd->buffer[off++]);
  690.       off -= 16;
  691.       putchar (' ');
  692.       for (j=0; j<16; j++) {
  693.         char c = p_cd->buffer[off++];
  694.         if (32<=c && c<=127)
  695.           putchar (c);
  696.         else
  697.           putchar ('.');
  698.       }
  699.       putchar ('\n');
  700.     }
  701.   }
  702. }
  703.  
  704. int Get_Device_And_Unit (void)
  705. {
  706.   int len;
  707.   char buf[10];
  708.   
  709.   len = GetVar ((UBYTE *) "CDROM_DEVICE", (UBYTE *) g_the_device,
  710.           sizeof (g_the_device), 0);
  711.   if (len < 0)
  712.     return 0;
  713.   if (len >= sizeof (g_the_device)) {
  714.     fprintf (stderr, "CDROM_DEVICE too long\n");
  715.     exit (1);
  716.   }
  717.   g_the_device[len] = 0;
  718.   
  719.   len = GetVar ((UBYTE *) "CDROM_UNIT", (UBYTE *) buf,
  720.           sizeof (buf), 0);
  721.   if (len < 0)
  722.     return 0;
  723.   if (len >= sizeof (buf)) {
  724.     fprintf (stderr, "CDROM_UNIT too long\n");
  725.     exit (1);
  726.   }
  727.   buf[len] = 0;
  728.   g_the_unit = atoi (buf);
  729.   
  730.   if (GetVar ((UBYTE *) "CDROM_TRACKDISK", (UBYTE *) buf,
  731.       sizeof (buf), 0) > 0) {
  732.     fprintf (stderr, "using trackdisk\n");
  733.     g_trackdisk = 1;
  734.   }
  735.  
  736.   if (GetVar ((UBYTE *) "CDROM_FASTMEM", (UBYTE *) buf,
  737.       sizeof (buf), 0) > 0) {
  738.     fprintf (stderr, "using fastmem\n");
  739.     g_memory_type = MEMF_FAST;
  740.   }
  741.  
  742.   return 1;
  743. }
  744.  
  745. void Select_Mode (CDROM *p_cd, int p_mode, int p_block_length)
  746. {
  747.   if (!Mode_Select (p_cd, p_mode, p_block_length))
  748.     fprintf (stderr, "mode select command failed!\n");
  749. }
  750.  
  751. void Show_Drive_Information (CDROM *p_cd)
  752. {
  753.   t_inquiry_data data;
  754.   int block_length;
  755.   
  756.   if (!Inquire (p_cd, &data)) {
  757.     fprintf (stderr, "cannot access CDROM drive\n");
  758.     return;
  759.   }
  760.  
  761.   if ((data.peripheral_type & 0x1f) != 5) {
  762.     if ((data.peripheral_type & 0x1f) == 8)
  763.       printf ("Drive type: medium changer\n");
  764.     else
  765.       printf ("WARNING: this is not a CDROM drive!\n");
  766.   }
  767.  
  768.   printf ("Vendor      : ");
  769.   fwrite (data.vendor, sizeof (data.vendor), 1, stdout);
  770.   printf ("\nProduct     : ");
  771.   fwrite (data.product, sizeof (data.product), 1, stdout);
  772.   printf ("\nRevision    : ");
  773.   fwrite (data.revision, sizeof (data.revision), 1, stdout);
  774.   putchar ('\n');
  775.   printf ("Conforms to : SCSI-%d\n", (int) (data.version & 0x7));
  776.   block_length = Block_Length (p_cd);
  777.   printf ("Block length: ");
  778.   if (block_length)
  779.     printf ("%d\n", block_length);
  780.   else
  781.     printf ("unknown\n");
  782. }
  783.  
  784. void Show_Table_Of_Contents (CDROM *p_cd)
  785. {
  786.   t_toc_header hdr;
  787.   t_toc_data *toc;
  788.   short i, len;
  789.   
  790.   if (!(toc = Read_TOC (p_cd, &hdr))) {
  791.     fprintf (stderr, "cannot read table of contents\n");
  792.     return;
  793.   }
  794.   
  795.   len = hdr.length / 8;
  796.   for (i=0; i<len; i++) {
  797.     if (toc[i].track_number == 0xAA)
  798.       printf ("Lead-out track at address %lu\n", toc[i].address);
  799.     else
  800.       printf ("Track %d: %s track, start address %lu\n",
  801.               (int) toc[i].track_number,
  802.           (toc[i].flags & 4) ? "data" : "audio",
  803.           toc[i].address);
  804.   }
  805. }
  806.  
  807. void Show_Catalog_Node (CDROM *p_cd, t_ulong p_node)
  808. {
  809.   t_mdb mdb;
  810.   t_node_descr *node;
  811.   t_hdr_node *hdr;
  812.   t_idx_record *idx;
  813.   t_leaf_record *leaf;
  814.   t_file_record *file;
  815.   t_dir_thread_record *thread;
  816.   char *cp;
  817.   int blk;
  818.   int i;
  819.   char buf[100];
  820.  
  821.   blk = HFS_Find_Master_Directory_Block (p_cd, &mdb);
  822.   if (blk < 0) {
  823.     fprintf (stderr, "cannot find master directory block\n");
  824.     return;
  825.   }
  826.  
  827.   node = HFS_Get_Node (p_cd, blk, &mdb, p_node);
  828.   if (!node) {
  829.     fprintf (stderr, "cannot find node %d\n", p_node);
  830.     return;
  831.   }
  832.   
  833.   switch (node->Type) {
  834.   case 0:
  835.     printf ("Index node:\n");
  836.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  837.             (int) node->NHeight);
  838.     idx = (t_idx_record *) ((char *) node + 0xe);
  839.     for (i=0; i<node->NRecs; i++, idx++) {
  840.       printf ("Parent ID = 0x%08lx, '", idx->parent_id);
  841.       fwrite (idx->name, idx->name_length, 1, stdout);
  842.       printf ("', pointer = %lu\n", idx->pointer);
  843.     }
  844.     break;
  845.   case 1:
  846.     printf ("Header node:\n");
  847.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  848.             (int) node->NHeight);
  849.     hdr = (t_hdr_node *) node;
  850.     printf ("Depth of tree:                  %u\n", hdr->Depth);
  851.     printf ("Number of root node:            %lu\n", hdr->Root);
  852.     printf ("Number of leaf records in tree: %lu\n", hdr->NRecs);
  853.     printf ("Number of first leaf node:      %lu\n", hdr->FNode);
  854.     printf ("Number of last leaf node:       %lu\n", hdr->LNode);
  855.     break;
  856.   case 2:
  857.     printf ("Map node:\n");
  858.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  859.             (int) node->NHeight);
  860.     break;
  861.   case 0xff:
  862.     printf ("Leaf node:\n");
  863.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  864.             (int) node->NHeight);
  865.     for (i=0; i<node->NRecs; i++) {
  866.       leaf = (t_leaf_record *) ((char *) node + ((short *) node)[255-i]);
  867.       cp = (char *) leaf + leaf->length + 1;
  868.       if ((leaf->length & 1) == 0)
  869.         cp++;
  870.       printf ("Parent ID = 0x%08lx, '", leaf->parent_id);
  871.       memcpy (buf, leaf->name, leaf->name_length);
  872.       Convert_Mac_Characters (buf, leaf->name_length);
  873.       fwrite (buf, leaf->name_length, 1, stdout);
  874.       printf ("'  (");
  875.       switch (*cp) {
  876.       case 1:
  877.         printf ("directory 0x%08lx)\n", *(t_ulong *)(cp+6));
  878.     break;
  879.       case 2:
  880.         file = (t_file_record *) cp;
  881.         printf ("file 0x%08lx)\n\tdata length %lu, "
  882.         "data extents %u-%u/%u-%u/%u-%u\n",
  883.         file->FlNum,
  884.         file->LgLen,
  885.         file->ExtRec[0].StABN, file->ExtRec[0].NumABlks,
  886.         file->ExtRec[1].StABN, file->ExtRec[1].NumABlks,
  887.         file->ExtRec[2].StABN, file->ExtRec[2].NumABlks);
  888.     printf ("\tresource length %lu, resource extents %u-%u/%u-%u/%u-%u\n",
  889.         file->RLgLen,
  890.         file->RExtRec[0].StABN, file->RExtRec[0].NumABlks,
  891.         file->RExtRec[1].StABN, file->RExtRec[1].NumABlks,
  892.         file->RExtRec[2].StABN, file->RExtRec[2].NumABlks);
  893.     printf ("\tfirst alloc blk for data fork: %u\n", file->StBlk);
  894.     printf ("\tfirst alloc blk for resource fork: %u\n", file->RStBlk);
  895.     break;
  896.       case 3:
  897.         thread = (t_dir_thread_record *) cp;
  898.         printf ("directory thread 0x%08lu '", thread->ParID);
  899.     fwrite (thread->CName, thread->CNameLen, 1, stdout);
  900.     printf ("')\n");
  901.     break;
  902.       case 4:
  903.         printf ("file thread)\n");
  904.     break;
  905.       default:
  906.         printf ("unknown)\n");
  907.     break;
  908.       }
  909.     }
  910.     break;
  911.   default:
  912.     printf ("unknown node type\n");
  913.     return;
  914.   }
  915.  
  916. }
  917.  
  918. void Play_Audio (CDROM *p_cd, int p_stop)
  919. {
  920.   int result;
  921.  
  922.   if (p_stop)
  923.     result = Stop_Play_Audio (p_cd);
  924.   else
  925.     result = Start_Play_Audio (p_cd);
  926.   
  927.   if (!result)
  928.     fprintf (stderr, "cannot perform operation\n");
  929. }
  930.  
  931. void main (int argc, char *argv[])
  932. {
  933.   atexit (Cleanup);
  934.  
  935.   if (argc < 2)
  936.     Usage ();
  937.  
  938.   if (!(UtilityBase = (struct Library *)
  939.          OpenLibrary ((UBYTE *) "utility.library", 37))) {
  940.     fprintf (stderr, "cannot open utility.library\n");
  941.     exit (1);
  942.   }
  943.  
  944.   if (!Get_Device_And_Unit ()) {
  945.     fprintf (stderr,
  946.       "Please set the following environment variables:\n"
  947.       "  CDROM_DEVICE    name of SCSI device\n"
  948.       "  CDROM_UNIT      unit number of CDROM drive\n"
  949.       "e.g.\n"
  950.       "  setenv CDROM_DEVICE scsi.device\n"
  951.       "  setenv CDROM_UNIT 2\n"
  952.       "Set the variable CDROM_TRACKDISK to any value if you\n"
  953.       "want to use trackdisk calls instead of SCSI-direct calls\n"
  954.       "Set the variable CDROM_FASTMEM to any value if you\n"
  955.       "want to use fast memory for SCSI buffers (does not work\n"
  956.       "with all SCSI devices!)\n"
  957.       );
  958.     exit (1);
  959.   }
  960.  
  961.   /* the following commands do not depend on the block length of
  962.    * the CDROM drive:
  963.    */
  964.   switch (argv[1][0]) {
  965.   case 'a':
  966.   case 'b':
  967.   case 'j':
  968.   case 'x':
  969.   case 'z':
  970.     g_ignore_blocklength = TRUE;
  971.   }
  972.  
  973.   cd = Open_CDROM (g_the_device, g_the_unit, g_trackdisk, g_memory_type,
  974.              STD_BUFFERS, FILE_BUFFERS);
  975.   if (!cd) {
  976.     fprintf (stderr, "cannot open CDROM, error code = %d\n", g_cdrom_errno);
  977.     exit (1);
  978.   }
  979.  
  980.   if (argv[1][0] == 'a' && argc == 2)
  981.     Show_Drive_Information (cd);
  982.   else if (argv[1][0] == 'b' && argc == 2)
  983.     Show_Table_Of_Contents (cd);
  984.   else if (argv[1][0] == 'c' && argc == 3)
  985.     Show_File_Contents (cd, argv[2]);
  986.   else if (argv[1][0] == 'd' && argc == 3)
  987.     Show_Dir_Contents (cd, argv[2], 0, argv[1]+1);
  988.   else if (argv[1][0] == 'e' && argc == 3)
  989.     Show_Dir_Contents (cd, argv[2], 1, argv[1]+1);
  990.   else if (argv[1][0] == 'f' && argc == 4)
  991.     Try_To_Open (cd, argv[2], argv[3]);
  992.   else if (argv[1][0] == 'i')
  993.     Check_Protocol (cd);
  994.   else if (argv[1][0] == 'j' && argc == 3)
  995.     Play_Audio (cd, atoi (argv[2]));
  996.   else if (argv[1][0] == 'm' && argc == 3)
  997.     Show_Catalog_Node (cd, atoi (argv[2]));
  998.   else if (argv[1][0] == 'o' && argc == 3)
  999.     Try_To_Open (cd, NULL, argv[2]);
  1000.   else if (argv[1][0] == 'r')
  1001.     Show_Root_Directory (cd);
  1002.   else if (argv[1][0] == 's' && argc == 3)
  1003.     Show_Sectors (cd, atoi (argv[2]), 1);
  1004.   else if (argv[1][0] == 's' && argc == 4)
  1005.     Show_Sectors (cd, atoi (argv[2]), atoi (argv[3]));
  1006.   else if (argv[1][0] == 't' && argc == 3)
  1007.     Try_To_Open (cd, (char *) -1, argv[2]);
  1008.   else if (argv[1][0] == 'v')
  1009.     Show_Primary_Volume_Descriptor (cd);
  1010.   else if (argv[1][0] == 'x' && argc == 3)
  1011.     Select_Mode (cd, atoi (argv[2]), 2048);
  1012.   else if (argv[1][0] == 'x' && argc == 4)
  1013.     Select_Mode (cd, atoi (argv[2]), atoi (argv[3]));
  1014.   else if (argv[1][0] == 'y' && argc == 3)
  1015.     Find_Block_Starting_With (cd, atoi (argv[2]));
  1016.   else if (argv[1][0] == 'z')
  1017.     Send_Test_Unit_Ready (cd);
  1018.   else
  1019.     Usage ();
  1020.  
  1021.   exit (0);
  1022. }
  1023.